package com.gmall.search.service;

import com.gmall.common.result.Result;
import com.gmall.model.search.Goods;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SearchService {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * {
     *     "keyword":"手机",
     *     "minPrice":100,
     *     "maxPrice":2000,
     *     "sortField":"price",
     *     "sortOrder":"desc",
     *     "tmName":"",
     *     "category3Name":""
     * }
     * @param page
     * @param size
     * @param searchMap
     * @return
     */
    public Result<Map> search(Integer page, Integer size, Map searchMap) {

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("price").order(SortOrder.ASC);
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(searchMap!=null){
            String keyword = (String) searchMap.get("keyword");
            if(!StringUtils.isEmpty(keyword)){
                MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders
                        .multiMatchQuery(keyword, "title", "tmName", "category3Name");
                boolQueryBuilder.must(multiMatchQueryBuilder);
            }
            //价格区间
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price");
            Integer minPrice = (Integer) searchMap.get("minPrice");
            Integer maxPrice = (Integer)searchMap.get("maxPrice");
            if(minPrice!=null){
                rangeQueryBuilder.gte(minPrice);
            }
            if(maxPrice!=null){
                rangeQueryBuilder.lte(maxPrice);
            }
            boolQueryBuilder.filter(rangeQueryBuilder);

            //排序
            String sortField = (String)searchMap.get("sortField");
            if(!StringUtils.isEmpty(sortField)){
                fieldSortBuilder = SortBuilders.fieldSort(sortField).order(SortOrder.ASC);//默认ASC
                String sortOrder = (String)searchMap.get("sortOrder");
                if(sortOrder.equalsIgnoreCase("DESC")){
                    fieldSortBuilder = SortBuilders.fieldSort(sortField).order(SortOrder.DESC);
                }
            }
            //如果品牌不为空，则按照品牌进行过滤
            String tmName = (String) searchMap.get("tmName");
            if(!StringUtils.isEmpty(tmName)){
                boolQueryBuilder.filter(QueryBuilders.termQuery("tmName",tmName));
            }
            //如果分类不为空，则按照分类进行过滤
            String category3Name = (String) searchMap.get("category3Name");
            if(!StringUtils.isEmpty(category3Name)){
                boolQueryBuilder.filter(QueryBuilders.termQuery("category3Name",category3Name));
            }
        }

        NativeSearchQuery query = nativeSearchQueryBuilder
                .withQuery(boolQueryBuilder)
                .withSort(fieldSortBuilder)
                .withPageable(PageRequest.of(page -1 ,size))
                .withHighlightBuilder(
                        new HighlightBuilder()
                                .preTags("<strong style='color:red'>")
                                .postTags("</strong>")
                                .field("title")
                )
                .addAggregation(
                        AggregationBuilders.terms("goods_tmName").field("tmName"))
                .addAggregation(AggregationBuilders.terms("goods_category3Name").field("category3Name"))
                .build();


        List<Goods> goodsList = new ArrayList<>();
        SearchHits<Goods> searchHits = elasticsearchRestTemplate.search(query, Goods.class);
        long total = searchHits.getTotalHits();
        List<SearchHit<Goods>> searchHitsArray = searchHits.getSearchHits();
        searchHitsArray.forEach(searchHit ->{
            Goods goods = searchHit.getContent();
            //高亮字段
            Map<String, List<String>> highlightFields = searchHit.getHighlightFields();

            List<String> titleList = highlightFields.get("title");
            if(titleList!=null&& titleList.size()>0){
                goods.setTitle(titleList.get(0));
            }
            /*List<Object> sortValues = searchHit.getSortValues();
            System.out.println(sortValues);*/
            System.out.println(goods);
            goodsList.add(goods);
        });

        Aggregations aggregations = searchHits.getAggregations();

        ParsedStringTerms goodsTmName_aggs = (ParsedStringTerms)aggregations.get("goods_tmName");

        Map<String,Long> tmAggs = new HashMap<>();
        List<? extends Terms.Bucket> tmName_buckets = goodsTmName_aggs.getBuckets();
        tmName_buckets.forEach(bucket -> {
            System.out.println(bucket.getKeyAsString());
            System.out.println(bucket.getDocCount());

            tmAggs.put(bucket.getKeyAsString(),bucket.getDocCount());
        });

        ParsedStringTerms goodsCategory3Name_aggs = (ParsedStringTerms)aggregations.get("goods_category3Name");

        Map<String,Long> category3Aggs = new HashMap<>();
        List<? extends Terms.Bucket> category3Name_buckets = goodsCategory3Name_aggs.getBuckets();
        category3Name_buckets.forEach(bucket -> {
            System.out.println(bucket.getKeyAsString());
            System.out.println(bucket.getDocCount());
            category3Aggs.put(bucket.getKeyAsString(),bucket.getDocCount());
        });

        Map map = new HashMap();
        map.put("total",total);
        map.put("goodsList",goodsList);
        map.put("tmAggs",tmAggs);
        map.put("category3Aggs",category3Aggs);
        return Result.ok(map);
    }
}
